#pragma once

#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <iomanip>
#include <map>

using namespace std;

namespace loirey
{
	class CConfiguration
	{
	private:
		map<string,string> PropetyMap;
		string strConfigurationFileName;
		wstring wstrConfigurationFileName;
		int fFileNameType;
	public:
		bool fDidLastAccessSucceed;

	protected:
		void GetAttribute(string strAttributeName, string& dstAttributeValue)
		{
			map<string,string>::iterator itr = PropetyMap.find(strAttributeName);
			if (itr==PropetyMap.end())
			{
				dstAttributeValue = "";
				fDidLastAccessSucceed = false;
			}
			else
			{
				dstAttributeValue = itr->second;
				fDidLastAccessSucceed = true;
			}
		}
	public:
		CConfiguration(string strConfigurationFileName)
		{
			this->strConfigurationFileName = strConfigurationFileName.c_str();
			fFileNameType = 0;

			fDidLastAccessSucceed = true;
		}

		CConfiguration(wstring wstrConfigurationFileName)
		{
			this->wstrConfigurationFileName = wstrConfigurationFileName.c_str();
			fFileNameType = 1;

			fDidLastAccessSucceed = true;
		}

		void Load()
		{
			ifstream inFile;
			string op,st;

			PropetyMap.clear();
			if (fFileNameType == 0)
				inFile.open(strConfigurationFileName.c_str());
			else
				inFile.open(wstrConfigurationFileName.c_str());

			int _ml = 100000;
			char* strTemp = new char[_ml+1];
			const char* pch;
			while (inFile>>op)
				for (;;)
				{
					strTemp[0] = strTemp[1] = strTemp[2] = strTemp[3] = 0;
					inFile.getline(strTemp, _ml);
					if (inFile.bad()) break;
					for (pch=strTemp; *pch; ++pch)
						if (*pch!=' ' && *pch!='\t' && *pch!='\r' && *pch!='\n')
							break;
					if (*pch)
					{
						PropetyMap[op] = pch;
						break;
					}
				}
			delete[] strTemp;
			//while (inFile>>op>>st)
			//	PropetyMap[op] = st;

			inFile.clear();
			inFile.close();

			fDidLastAccessSucceed = true;
		}

		void Print(ostream& outStream)
		{
			map<string,string>::iterator itr;

			outStream<<"Configuration:"<<endl<<endl;
			for ( itr = PropetyMap.begin(); itr != PropetyMap.end(); ++itr )
				if ((itr->second)[0]!='/' && (itr->second)[1]!='/')
					outStream<<setw(40)<<itr->first<<"    "<<itr->second<<endl;
			outStream<<endl;
		}

		int GetInt(string strIntName)
		{
			string tmp;
			GetAttribute(strIntName,tmp);
			return (int)atoi(tmp.c_str());
		}
		double GetDouble(string strDoubleName)
		{
			string tmp;
			GetAttribute(strDoubleName,tmp);
			return (double)(atof(tmp.c_str()));
		}
		string GetString(string strStringName)
		{
			string tmp;
			GetAttribute(strStringName,tmp);
			return tmp;
		}

		int GetInt(string strIntName, int DefaultValue)
		{
			int ret = GetInt(strIntName);
			return (fDidLastAccessSucceed ? ret : DefaultValue);
		}
		double GetDouble(string strDoubleName, double DefaultValue)
		{
			double ret = GetDouble(strDoubleName);
			return (fDidLastAccessSucceed ? ret : DefaultValue);
		}
		string GetString(string strStringName, string DefaultValue)
		{
			string ret = GetString(strStringName);
			return (fDidLastAccessSucceed ? ret : DefaultValue);
		}
	};

	class CCommandLineParameters
	{
	protected:
		char* _para;
	public:
		CSimpleTypeArray<char*> Args;
		int CurrentParameterIndex;
		
	protected:
		void myRelease()
		{
			if (_para == NULL) return;
			delete[] _para;
			_para = NULL;
		}
		void BuildArgs()
		{
			bool fl;
			char* op;

			Args.Clear();
			for ( fl = false, op = _para; *op; ++op )
			{
				if (*op==' ' || *op=='\t' || *op=='\n' || *op=='\r' || *op<32)
				{
					fl = false;
					*op = 0;
					continue;
				}
				if (fl) continue;
				Args.PushBack(op);
				fl = true;
			}
			Rewind();
		}
	public:
		CCommandLineParameters()
		{
			_para = NULL;
		}
		~CCommandLineParameters()
		{
			myRelease();
		}
		void myInit(const char* CommandLineParameters)
		{
			myRelease();
			_para = new char[strlen(CommandLineParameters) + 1];
			strcpy(_para, CommandLineParameters);
			BuildArgs();
		}
		void myInit(int nArgs, char* const* sArgs)
		{
			int i,j;
			const char* op;

			myRelease();
			j = 0;
			for ( i = 0; i < nArgs; ++i ) j += (int)strlen(sArgs[i]) + 1;
			_para = new char[j + 1];
			j = 0;
			for ( i = 0; i < nArgs; ++i )
			{
				for ( op = sArgs[i]; *op; ++op )
					_para[j++] = *op;
				_para[j++] = ' ';
			}
			_para[j] = 0;
			BuildArgs();
		}
		void GetParameter(char* dstStr, int ParameterIndex)
		{
			if (ParameterIndex<0 || ParameterIndex>=(int)Args.Size)
				dstStr[0] = 0;
			else
				strcpy(dstStr, Args.pElement[ParameterIndex]);
		}
		void GetParameter(string& dstStr, int ParameterIndex)
		{
			if (ParameterIndex<0 || ParameterIndex>=(int)Args.Size)
				dstStr = "";
			else
				dstStr = string(Args.pElement[ParameterIndex]);
		}
		void Rewind()
		{
			CurrentParameterIndex = 0;
		}
		void GetNextParameter(string& dstStr)
		{
			GetParameter(dstStr, CurrentParameterIndex++);
		}
		void GetNextParameter(char* dstStr)
		{
			GetParameter(dstStr, CurrentParameterIndex++);
		}
	};
}

